package cn.patient.pp.module.fiveInOne.service;

import cn.hutool.core.util.StrUtil;
import cn.patient.pp.framework.common.pojo.PageResult;
import cn.patient.pp.framework.common.util.object.BeanUtils;
import cn.patient.pp.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.patient.pp.framework.security.core.LoginUser;
import cn.patient.pp.framework.security.core.util.SecurityFrameworkUtils;
import cn.patient.pp.module.fiveInOne.controller.admin.vo.KeyPersonProtectionImportExcelVO;
import cn.patient.pp.module.fiveInOne.controller.admin.vo.KeyPersonProtectionPageReqVO;
import cn.patient.pp.module.fiveInOne.controller.admin.vo.KeyPersonProtectionRespVO;
import cn.patient.pp.module.fiveInOne.controller.admin.vo.KeyPersonProtectionSaveReqVO;
import cn.patient.pp.module.fiveInOne.dal.dataobject.KeyPersonProtectionDO;
import cn.patient.pp.module.fiveInOne.dal.mysql.KeyPersonProtectionMapper;
import cn.patient.pp.module.fiveInOne.util.CommonUtils;
import cn.patient.pp.module.patients.controller.admin.vo.importExecl.ImportRespVO;
import cn.patient.pp.module.patients.controller.admin.vo.importExecl.PatientsDOExeclVO;
import cn.patient.pp.module.patients.dal.dataobject.patients.PatientsDODO;
import cn.patient.pp.module.patients.dal.mysql.patients.PatientsDOMapper;
import cn.patient.pp.module.patients.framework.web.config.Config;
import cn.patient.pp.module.patients.framework.web.config.LogRecordConstants;
import cn.patient.pp.module.patients.framework.web.config.async.AsyncTaskServie;
import cn.patient.pp.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.patient.pp.module.system.dal.dataobject.dept.DeptDO;
import cn.patient.pp.module.system.dal.dataobject.user.AdminUserDO;
import cn.patient.pp.module.system.service.dept.DeptService;
import cn.patient.pp.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mzt.logapi.starter.annotation.LogRecord;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static cn.patient.pp.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.patient.pp.module.infra.enums.ErrorCodeConstants.KEY_PERSON_PROTECTION_NOT_EXISTS;
import static cn.patient.pp.module.patients.service.PatientsDOServiceImpl.splitList;
import static cn.patient.pp.module.system.dal.redis.RedisKeyConstants.*;
import static cn.patient.pp.module.system.dal.redis.RedisKeyConstants.FOLLOW_IP_TRENDS;

/**
 * @author liqingsong
 * @version 1.0
 * Create by 2025/6/11
 */
@Service
@Validated
public class KeyPersonProtectionServiceImpl implements KeyPersonProtectionService {
    @Resource
    private PatientsDOMapper patientsDOMapper;

    @Resource
    private KeyPersonProtectionMapper keyPersonProtectionMapper;

    @Resource
    private DeptService deptService;

    @Resource
    private AdminUserService adminUserService;

    @Resource
    private AsyncTaskServie asyncTaskServie;

    @Override
    public Integer createKeyPersonProtection(KeyPersonProtectionSaveReqVO createReqVO) {
        //查身份证
        if (createReqVO.getPatientCode() != null) {
            // 查询身份证号
            PatientsDODO patientsDODO = patientsDOMapper.selectOne(new QueryWrapper<PatientsDODO>()
                    .eq("patient_code", createReqVO.getPatientCode()));
            if (patientsDODO != null) {
                createReqVO.setIdNumber(patientsDODO.getIdNumber());
            }
        }
        if (createReqVO.getIdNumber() != null) {
            // 查询身份证号
            PatientsDODO patientsDODO = patientsDOMapper.selectOne(new QueryWrapper<PatientsDODO>()
                    .eq("id_number", createReqVO.getIdNumber()));
            if (patientsDODO != null) {
                createReqVO.setDeptId(patientsDODO.getDeptId());
            }
        }
        // 插入
        KeyPersonProtectionDO keyPersonProtection = BeanUtils.toBean(createReqVO, KeyPersonProtectionDO.class);
        keyPersonProtectionMapper.insert(keyPersonProtection);
        // 返回
        return keyPersonProtection.getId();
    }

    @Override
    public void updateKeyPersonProtection(KeyPersonProtectionSaveReqVO updateReqVO) {
        // 校验存在
        validateKeyPersonProtectionExists(updateReqVO.getId());
        // 更新
        KeyPersonProtectionDO updateObj = BeanUtils.toBean(updateReqVO, KeyPersonProtectionDO.class);
        keyPersonProtectionMapper.updateById(updateObj);
    }

    @Override
    public void deleteKeyPersonProtection(Integer id) {
        // 校验存在
        validateKeyPersonProtectionExists(id);
        // 删除
        keyPersonProtectionMapper.deleteById(id);
    }

    private void validateKeyPersonProtectionExists(Integer id) {
        if (keyPersonProtectionMapper.selectById(id) == null) {
            throw exception(KEY_PERSON_PROTECTION_NOT_EXISTS);
        }
    }

    @Override
    public KeyPersonProtectionRespVO getKeyPersonProtection(Integer id) {
        return keyPersonProtectionMapper.selectDetailById(id);
    }

    @Override
    public PageResult<KeyPersonProtectionDO> getKeyPersonProtectionPage(KeyPersonProtectionPageReqVO pageReqVO) {
        //查身份证
        if (pageReqVO.getPatientCode() != null) {
            //由新筛查上报的不允许查随访记录
            if (Config.HAS_DIAGNOSED_PATIENT_CODE.equals(pageReqVO.getPatientCode())){
                return null;
            }else{
                // 查询身份证号
                PatientsDODO patientsDODO = patientsDOMapper.selectOne(new QueryWrapper<PatientsDODO>()
                        .eq("patient_code", pageReqVO.getPatientCode()));
                if (patientsDODO!=null){
                    pageReqVO.setIdNumber(patientsDODO.getIdNumber());
                }
                pageReqVO.setPatientCode(null);
            }

        }
        //查部门
        List<Long> loginUserDeptIds = getLoginUserDeptIds();
        List<Long> deptIds = pageReqVO.getDeptIds();
        if (deptIds == null || deptIds.isEmpty()) {
            // 如果没有指定部门，则使用登录用户所在的部门
            deptIds = loginUserDeptIds;
        } else {
            // 如果指定了部门，则需要确保这些部门是登录用户所在的部门或其子部门，取交集
            deptIds.retainAll(loginUserDeptIds);
        }

        return keyPersonProtectionMapper.selectPage(pageReqVO, deptIds);
    }

    private List<Long> getLoginUserDeptIds() {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        Long userId = null;
        if (loginUser != null) {
            userId = loginUser.getId();
        }
        AdminUserDO user = adminUserService.getUser(userId);
        return deptService.getDeptIdsAndOwnId(user.getDeptId());
    }

    @Override
    @LogRecord(success = LogRecordConstants.PROTECTION_IMPORT_SUCCESS,
            operator = "{{#currentUser}}",
            type = LogRecordConstants.PROTECTION,
            fail = "导入五帮一失败，失败原因：「{{#_errorMsg}}」",
            subType = LogRecordConstants.PROTECTION_IMPORT,bizNo = LogRecordConstants.PROTECTION_IMPORT_BIZ_NO)
    public ImportRespVO importKeyPersonProtectionList(List<KeyPersonProtectionImportExcelVO> list, Boolean updateSupport) throws InterruptedException {

        // 遍历，逐个创建 or 更新
        ImportRespVO respVO = ImportRespVO.builder().createUsernames(new ArrayList<>())
                .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).total(new AtomicInteger(0)).build();

        List<DeptDO> deptList = deptService.getDeptList(new DeptListReqVO());
        List<PatientsDODO> patientsDODOList = patientsDOMapper.selectIdNumberAndDeptIdList();
        // 保留第一个出现的 DeptDO
        Map<String, Long> deptMap = deptList.stream().collect(
                Collectors.toMap(
                        DeptDO::getWgCode, DeptDO::getId,
                        (existing, replacement) -> existing));

        for (KeyPersonProtectionImportExcelVO excelVO : list) {
            // 赋值部门id
            if (StrUtil.isNotBlank(excelVO.getGridCode())) {
                excelVO.setDeptId(deptMap.get(excelVO.getGridCode()));
            }

            if (StrUtil.isNotBlank(excelVO.getIdNumber())) {
                // 赋值出生日期
                excelVO.setBirthDate(CommonUtils.extractBirthDateFromIdNumber(excelVO.getIdNumber()));

                // 赋值部门id
                patientsDODOList.stream().filter(patientsDODO -> excelVO.getIdNumber().equals(patientsDODO.getIdNumber())).findFirst().ifPresent(patientsDO -> excelVO.setDeptId(patientsDO.getDeptId()));
            }
        }

        // 切分数据
        List<List<KeyPersonProtectionImportExcelVO>> batchList = splitList(list, Config.BATHCH_SIZE);

        // 定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                Config.CORE_THREAD_NUM, Config.MAX_THREAD_NUM, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        // 将任务提交给线程池执行，同时提供一个队列保存执行结果，你可以“谁先完成谁先处理”。
        CompletionService<Boolean> completionService = new ExecutorCompletionService<>(executor);
        // 多线程分批发入数据库
        long start = System.currentTimeMillis(); // 记录开始时间
        for (List<KeyPersonProtectionImportExcelVO> batch : batchList) {
            completionService.submit(() -> {
                keyPersonProtectionMapper.insertOrUpdate(batch);
                respVO.getTotal().addAndGet(batch.size());
                return true;
            });
        }

        // 检查异常
        for (int i = 0; i < batchList.size(); i++) {
            Future<Boolean> result = completionService.take(); // 按完成顺序取出
            long end = System.currentTimeMillis();   // 记录结束时间
            System.out.println("线程[" + Thread.currentThread().getName() + "] 处理耗时：" + (end - start) + " ms");
            try {
                result.get(); // 捕获异常
            } catch (Exception e) {
                e.printStackTrace(); // 可换成记录日志
            }
        }
        executor.shutdown();

        return respVO;
    }
}

